package com.jacob.androidframe.util;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.ByteArrayOutputStream;
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;

public class UtilStream
{
	// 缓存大小
	public static final int		BUFFER_SIZE		= 4096;
	// 默认编码
	public static final String	DEFAULT_CHARSET	= "UTF-8";

	/**
	 * 传入输入流，从该输入流中读取字节数组并返回。
	 * 传入的输入流不会被关闭。
	 * 
	 * @param pInputStream
	 *            输入流
	 * @return 字节数组
	 * @throws IOException
	 *             若读取过程中出错，则抛出异常。
	 */
	public static byte[] readStreamAsBytesArray(InputStream pInputStream) throws IOException
	{
		if (pInputStream == null) {
			return null;
		}

		BufferedInputStream _BufferedInputStream = null;
		// 内存输出流，将数据写入内存
		ByteArrayOutputStream _ByteArrayOutputStream = new ByteArrayOutputStream();
		byte[] _ResultArray = null;

		try {
			_BufferedInputStream = new BufferedInputStream(pInputStream, BUFFER_SIZE * 3);
			byte[] _Buffer = new byte[BUFFER_SIZE];

			// 从pInputStream中将数据写入内存
			int _Len;
			while ((_Len = _BufferedInputStream.read(_Buffer)) != -1) {
				_ByteArrayOutputStream.write(_Buffer, 0, _Len);
			}
			_ByteArrayOutputStream.flush();

			_ResultArray = _ByteArrayOutputStream.toByteArray();
		} finally {
			if (_BufferedInputStream != null) {
				_BufferedInputStream.close();
			}
			if (_ByteArrayOutputStream != null) {
				_ByteArrayOutputStream.close();
			}
		}

		return _ResultArray;
	}

	/**
	 * 将一个输入流解码为String对象并返回。
	 * 
	 * @param pInputStream
	 *            输入流
	 * @param pEncoding
	 *            字符使用的编码，若传入无效编码，则使用默认编码。
	 * @return 解码后的String对象，若输入流为null，则返回null。
	 * @throws IOException
	 */
	public static String readStreamAsString(InputStream pInputStream, String pEncoding) throws IOException
	{
		if (pInputStream == null) {
			return null;
		}

		InputStreamReader _InputStreamReader = null;
		try {
			_InputStreamReader = new InputStreamReader(pInputStream, pEncoding);
		} catch (Exception e) {
			try {
				_InputStreamReader = new InputStreamReader(pInputStream, DEFAULT_CHARSET);
			} catch (UnsupportedEncodingException e1) {
				throw new RuntimeException(e1);
			}
		}

		BufferedReader _BufferedReader = new BufferedReader(_InputStreamReader, BUFFER_SIZE * 3);

		StringBuilder _StringBuilder = new StringBuilder();
		int _Len;
		char[] _CharBuff = new char[BUFFER_SIZE];

		try {
			while ((_Len = _BufferedReader.read(_CharBuff)) != -1) {
				_StringBuilder.append(_CharBuff, 0, _Len);
			}
		} finally {
			if (_BufferedReader != null) {
				_BufferedReader.close();
			}
			if (_InputStreamReader != null) {
				_InputStreamReader.close();
			}
		}

		return _StringBuilder.toString();
	}

	/**
	 * 将一个输入流解码为Bitmap对象并返回。
	 * 
	 * @param pInputStream
	 *            输入流
	 * @return 解码后的Bitmap对象，若输入流为null，或其中的数据无法解析为Bitmap对象，则返回null。
	 */
	public static Bitmap readStreamAsBitmap(InputStream pInputStream)
	{
		return BitmapFactory.decodeStream(new FlushedInputStream(pInputStream));
	}

	public static void writeBytesArrayToStream(OutputStream pOutputStream, byte[] pByteArray) throws IOException
	{
		if (pOutputStream == null || pByteArray == null) {
			return;
		}

		BufferedOutputStream _BufferedOutputStream = new BufferedOutputStream(pOutputStream, BUFFER_SIZE * 3);

		try {
			_BufferedOutputStream.write(pByteArray);
			_BufferedOutputStream.flush();
		} finally {
			if (_BufferedOutputStream != null) {
				_BufferedOutputStream.close();
			}
		}
	}

	public static void writeStringToStream(OutputStream pOutputStream, String pString, String pEncoding) throws IOException
	{
		if (pOutputStream == null || pString == null) {
			return;
		}
		
		OutputStreamWriter _OutputStreamWriter = null;
		try {
			_OutputStreamWriter = new OutputStreamWriter(pOutputStream, pEncoding);
		} catch (Exception e) {
			try {
				_OutputStreamWriter = new OutputStreamWriter(pOutputStream, pEncoding);
			} catch (UnsupportedEncodingException e1) {
				throw new RuntimeException(e1);
			}
		}

		BufferedWriter _BufferedWriter = new BufferedWriter(_OutputStreamWriter, BUFFER_SIZE * 3);

		try {
			_BufferedWriter.write(pString);
			_BufferedWriter.flush();
			
		} finally {
			if (_BufferedWriter != null) {
				_BufferedWriter.close();
			}
			if (_OutputStreamWriter != null) {
				_OutputStreamWriter.close();
			}
		}
	}

	/**
	 * A bug in the previous versions of BitmapFactory.decodeStream()
	 * may prevent this code from working over a slow connection.
	 * Decode a new FlushedInputStream(inputStream) instead to fix the problem.
	 * 2010年7月前的BitmapFactory.decodeStream()方法有个BUG，会导致解析缓慢。
	 * 使用本类将InputStream包装一下，再传给decodeStream()方法，可以防止BUG出现。
	 * 新版本的BitmapFactory无此BUG。
	 * 
	 * @author 王超
	 */
	private static class FlushedInputStream extends FilterInputStream
	{
		public FlushedInputStream(InputStream pInputStream)
		{
			super(pInputStream);
		}

		@Override
		public long skip(long n) throws IOException
		{
			long totalBytesSkipped = 0L;
			while (totalBytesSkipped < n) {
				long bytesSkipped = in.skip(n - totalBytesSkipped);
				if (bytesSkipped == 0L) {
					int b = read();
					if (b < 0) {
						break; // we reached EOF
					} else {
						bytesSkipped = 1; // we read one byte
					}
				}
				totalBytesSkipped += bytesSkipped;
			}
			return totalBytesSkipped;
		}
	}
}
